# !/usr/bin/env python
# -*-coding:utf-8 -*-

"""
# Author     ：skyTree
# version    ：python 3.11
# Description：JWT鉴权
"""
from datetime import datetime, timedelta
import jwt
from fastapi import Depends, HTTPException
from fastapi.security import SecurityScopes
from jwt import PyJWTError
from pydantic import ValidationError
from starlette import status
from core.Token import MyOAuth2PasswordBearer
from config import settings
from models.base import User, Menu

oauth2_scheme = MyOAuth2PasswordBearer(tokenUrl=settings.SWAGGER_UI_OAUTH2_REDIRECT_URL)


def create_access_token(data: dict) -> str:
    """
    创建token
    :param data: 加密数据
    :return: jwt
    """
    token_data = data.copy()
    # token超时时间
    expire = datetime.utcnow() + timedelta(minutes=settings.JWT_ACCESS_TOKEN_EXPIRE_MINUTES)
    # 向jwt加入超时时间
    token_data.update({"exp": expire})
    # jwt加密
    jwt_token = jwt.encode(token_data, settings.JWT_SECRET_KEY, algorithm=settings.JWT_ALGORITHM)

    return jwt_token


async def check_permissions(security_scopes: SecurityScopes, token=Depends(oauth2_scheme)):
    """
    校验token
    :param token:
    :return:
    """
    if token == 'login':
        return ''
    try:
        # token解密
        payload = jwt.decode(token, settings.JWT_SECRET_KEY, algorithms=[settings.JWT_ALGORITHM])

        if payload:
            # 用户ID
            user_id = payload.get("user_id", None)
            # 用户类型
            user_name = payload.get("user_name", None)

            # 无效用户信息
            if user_id is None or user_name is None:
                credentials_exception = HTTPException(
                    status_code=status.HTTP_401_UNAUTHORIZED,
                    detail="无效凭证!",
                    headers={"WWW-Authenticate": f"Bearer{token}"},
                )
                raise credentials_exception

        else:
            credentials_exception = HTTPException(
                status_code=status.HTTP_401_UNAUTHORIZED,
                detail="无效凭证!",
                headers={"WWW-Authenticate": f"Bearer {token}"},
            )
            raise credentials_exception

    except jwt.ExpiredSignatureError:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="凭证已证过期",
            headers={"WWW-Authenticate": f"Bearer {token}"},
        )

    except jwt.InvalidTokenError:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="无效凭证!",
            headers={"WWW-Authenticate": f"Bearer {token}"},
        )

    except (PyJWTError, ValidationError):
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="无效凭证!",
            headers={"WWW-Authenticate": f"Bearer {token}"},
        )
    user = await User.get_or_none(id=user_id).prefetch_related('roles')
    if not user:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="无效凭证!",
            headers={"WWW-Authenticate": f"Bearer {token}"},
        )
    user = await User.get(id=user_id).prefetch_related('roles__menus')  # 预加载用户角色及其关联的菜单
    menus = [dict(menu)['scopes'] async for role in user.roles for menu in role.menus]
    is_pass = await Menu.filter(roles__users__id=user_id, scopes__in=set(security_scopes.scopes)).all()
    if security_scopes.scopes:
        if not is_pass:
            raise HTTPException(
                status_code=status.HTTP_403_FORBIDDEN,
                detail="您没有该权限!",
                headers={"scopes": security_scopes.scope_str},
            )
